using System;
using System.Net;

namespace SmartBoard.Core.Networking
{
    /// <summary>
    /// Server connection host.
    /// </summary>
    public class SocketServer : BaseSocketConnectionHost
    {
        #region Constructor

        public SocketServer(CallbackThreadType callbackThreadType, ISocketService socketService)
            : base(HostType.Server, callbackThreadType, socketService, DelimiterType.None, null, 2048, 2048, 0, 0)
        { }

        public SocketServer(CallbackThreadType callbackThreadType, ISocketService socketService, DelimiterType delimiterType, byte[] delimiter)
            : base(HostType.Server, callbackThreadType, socketService, delimiterType, delimiter, 2048, 2048, 0, 0)
        { }

        public SocketServer(CallbackThreadType callbackThreadType, ISocketService socketService, DelimiterType delimiterType, byte[] delimiter, int socketBufferSize, int messageBufferSize)
            : base(HostType.Server, callbackThreadType, socketService, delimiterType, delimiter, socketBufferSize, messageBufferSize, 0, 0)
        { }

        public SocketServer(CallbackThreadType callbackThreadType, ISocketService socketService, DelimiterType delimiterType, byte[] delimiter, int socketBufferSize, int messageBufferSize, int idleCheckInterval, int idleTimeOutValue)
            : base(HostType.Server, callbackThreadType, socketService, delimiterType, delimiter, socketBufferSize, messageBufferSize, idleCheckInterval, idleTimeOutValue)
        { }

        #endregion

        #region Public Methods

        public SocketListener AddListener(string name, IPEndPoint localEndPoint, EncryptionType encryptionType, CompressionType compressionType, ICryptoService cryptoService, byte backLog, byte acceptThreads)
        {
            if (IsDisposed) return null;

            var listener = new SocketListener(this, name, localEndPoint, encryptionType, compressionType, cryptoService, backLog, acceptThreads);
            AddCreator(listener);
            return listener;
        }

        public override void Stop()
        {
            if (!IsDisposed)
            {
                StopCreators();
                StopConnections();
            }
            base.Stop();
        }
        #endregion

        #region Internal Methods

        internal override void BeginReconnect(ClientSocketConnection connection) 
        { }

        internal override void BeginSendToAll(ServerSocketConnection connection, byte[] buffer, bool includeMe)
        {
            if (!IsDisposed)
            {
                BaseSocketConnection[] items = GetSocketConnections();

                if (items != null)
                {
                    var loopSleep = 0;

                    foreach (var cnn in items)
                    {
                        if (!IsDisposed)
                        {
                            try
                            {
                                if (includeMe || connection != cnn)
                                {
                                    var localBuffer = new byte[buffer.Length];
                                    Buffer.BlockCopy(buffer, 0, localBuffer, 0, buffer.Length);

                                    BeginSend(cnn, localBuffer, true);
                                }
                            }
                            finally
                            {
                                ThreadUtils.LoopSleep(ref loopSleep);
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
        }

        internal override void BeginSendTo(BaseSocketConnection connection, byte[] buffer)
        {
            if (IsDisposed) return;

            BeginSend(connection, buffer, true);
        }

        #endregion
    }
}